﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;

using ERPStore.Web.Routing;
using ERPStore.Web.Extensions;

using CloudSoft.Extensions;

using ERPStore.Extensions;

namespace ERPStore.Web.Controllers
{
	public abstract class StoreController : AsyncController
	{
		public StoreController()
		{
			SearchOptimizationService = GlobalConfiguration.Configuration.DependencyResolver.GetService<Services.IOptimizationService>();
			Logger = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Logging.ILogger>();
			LocalizationService = GlobalConfiguration.Configuration.DependencyResolver.GetService<ERPStore.Services.ILocalizationService>();
			EventPublisherService = GlobalConfiguration.Configuration.DependencyResolver.GetService<EventBrokR.IPublisher>();
		}

		protected Services.IOptimizationService SearchOptimizationService { get; set; }
		public ERPStore.Logging.ILogger Logger { get; set; }
		public ERPStore.Services.ILocalizationService LocalizationService { get; set; }
		public EventBrokR.IPublisher EventPublisherService { get; set; }

		protected Settings.WebSiteSettings SiteSettings
		{
			get
			{
				return GlobalConfiguration.Configuration.Settings;
			}
		}

		protected virtual new ERPStore.Models.UserPrincipal User
		{
			get
			{
				return HttpContext.User as ERPStore.Models.UserPrincipal;
			}
		}

		protected override void Initialize(System.Web.Routing.RequestContext requestContext)
		{
			base.Initialize(requestContext);
			if (LocalizationService.Enabled)
			{
				InitializeLocalization();
			}
			else
			{
				string currentLanguage = GlobalConfiguration.Configuration.Settings.Language.Name;
				var language = GlobalConfiguration.Configuration.Settings.Language;
				try
				{
					language = ERPStore.Models.Language.GetByName(currentLanguage);
				}
				catch { }
				var ci = new System.Globalization.CultureInfo(language.Id);

				// Fixe la culture du thread en cours
				// Change le format de date et autres
				System.Threading.Thread.CurrentThread.CurrentCulture = ci;
				System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
			}
		}

		protected override ViewResult View(IView view, object model)
		{
			var result = base.View(view, model);
			try
			{
				SearchOptimizationService.GenerateMetasInformations(this.HttpContext, ViewData.Model);
			}
			catch(Exception ex)
			{
				LogError(Logger, ex);
			}
			bool isNewVisitor = false;
			result.ViewBag.VisitorId = HttpContext.GetOrCreateVisitorId(out isNewVisitor);
			return result;
		}

		protected override ViewResult View(string viewName, string masterName, object model)
		{
			var result = base.View(viewName, masterName, model);
			try
			{
				SearchOptimizationService.GenerateMetasInformations(this.HttpContext, ViewData.Model);
			}
			catch (Exception ex)
			{
				LogError(Logger, ex);
			}
			bool isNewVisitor = false;
			result.ViewBag.VisitorId = HttpContext.GetOrCreateVisitorId(out isNewVisitor);
			return result;
		}

		protected override RedirectResult Redirect(string url)
		{
			if (url.IsNullOrTrimmedEmpty())
			{
				throw new ArgumentException("Url cannot be null");
			}
			var result = base.Redirect(url);
			return result;
		}

		protected RedirectToRouteResult RedirectToERPStoreRoute(string routeName)
        {
			return RedirectToERPStoreRoute(routeName, null);
        }

        protected RedirectToRouteResult RedirectToERPStoreRoute(string routeName, object routeValues)
        {
			routeName = this.HttpContext.ResolveRouteName(routeName);
			var result = RedirectToRoute(routeName, routeValues);

			if (HttpContext.Request["trace"] == "off")
			{
				return result;
			}
			bool isNewVisitor = false;
			var @event = new ERPStore.Events.TrackerEvent()
			{
				// HttpContextBase = HttpContext,
				// ActionResult = result,
				ControllerName = this.GetType().Name,
				ActionName = "redirect",
				UserAgent = Request.UserAgent,
				UserHostAddress = Request.UserHostAddress,
				VisitorId = HttpContext.GetOrCreateVisitorId(out isNewVisitor),
			};

			EventPublisherService.PublishAsync(@event);

            return result;
        }

		protected RedirectResult RedirectWithTracking(string url)
		{
			var result = base.Redirect(url);
			bool isNewVisitor = false;
			var @event = new ERPStore.Events.TrackerEvent()
			{
				// HttpContextBase = HttpContext,
				// ActionResult = result,
				ControllerName = this.GetType().Name,
				ActionName = "redirect",
				UserAgent = Request.UserAgent,
				UserHostAddress = Request.UserHostAddress,
				VisitorId = HttpContext.GetOrCreateVisitorId(out isNewVisitor),
				ResponseStatusCode = 200,
			};

			EventPublisherService.PublishAsync(@event);

			return result;
		}

		protected int GetPageId(int? page)
		{
			var result = Math.Max(0,page.GetValueOrDefault(0) - 1);
			return result;
		}

		protected int GetPageId()
		{
			var page = Request[ERPStore.GlobalConfiguration.Configuration.Settings.Catalog.PageParameterName];
			var pageId = 0;
			int.TryParse(page, out pageId);
			return Math.Max(0, pageId - 1);
		}

		protected int GetPageSize()
		{
			var pageSize = Request[ERPStore.GlobalConfiguration.Configuration.Settings.Catalog.PageSizeParameterName];
			int size = ERPStore.GlobalConfiguration.Configuration.Settings.Catalog.PageSize;
			if (!pageSize.IsNullOrTrimmedEmpty())
			{
				int.TryParse(pageSize, out size);
			}
			return Math.Max(1, size);
		}

		protected void LogError(ERPStore.Logging.ILogger logger, Exception ex)
		{
			ex.Data.Add("Message", ex.Message);
			ex.Data.Add("machineName", Environment.MachineName);
			ex.Data.Add("host", Request.Url.Host);
			// ex.Data.Add("visitorId", visitorId);
			ex.Data.Add("userHostAddress", Request.UserHostAddress);
			ex.Data.Add("userHostName", Request.UserHostName);
			ex.Data.Add("url", Request.RawUrl);
			ex.Data.Add("referer", Request.UrlReferrer);
			ex.Data.Add("applicationPath", Request.ApplicationPath);
			ex.Data.Add("user-agent", Request.Headers["User-Agent"]);
			ex.Data.Add("cookie", Request.Headers["Cookie"]);
			ex.Data.Add("httpmethod", Request.HttpMethod);
			if (Request.Form != null
				&& Request.Form.Count > 0)
			{
				ex.Data.Add("begin-form", "-----------------------");
				foreach (var item in Request.Form.AllKeys)
				{
					if (ex.Data.Contains(item))
					{
						continue;
					}
					ex.Data.Add(item, Request.Form[item]);
				}
				ex.Data.Add("end-form", "-----------------------");
			}
			if (User.Identity.IsAuthenticated
				&& User.Identity is ERPStore.Models.UserPrincipal)
			{
				ex.Data.Add("user", User.CurrentUser.Login);
			}
			else
			{
				ex.Data.Add("user", "anonymous");
			}
			logger.Error(ex);
		}

		protected void MovedPermanently(string location)
		{
			Response.Clear();
			Response.StatusCode = 301;
			Response.StatusDescription = "Moved Permanently";
			Response.AppendHeader("Location", location);
			Response.End();
		}

        public ActionResult HideReferer(string url)
        {
            if (url.IsNullOrTrimmedEmpty())
            {
                url = Request["url"];
                if (url.IsNullOrTrimmedEmpty())
                {
                    return new EmptyResult();
                }
            }

            var bts = System.Convert.FromBase64String(url);
            var decodedUrl = System.Text.Encoding.UTF8.GetString(bts);

            var sb = new System.Text.StringBuilder();
            sb.Append("<html>");
            sb.Append("<head>");
            sb.AppendFormat("<meta http-equiv=\"refresh\" content=\"0;URL={0}\" />", decodedUrl);
            sb.Append("</head>");
            sb.Append("<body>");
            sb.Append("</body>");
            sb.Append("</html>");
            return Content(sb.ToString(), "text/html");
        }

		private void InitializeLocalization()
		{
			string currentLanguage = null;

			// Recherche d'un parametre dans l'url courrante (Changement de langue)
			var languageParameter = HttpContext.Request["language"];
			if (languageParameter != null)
			{
				currentLanguage = languageParameter.ToLower();
			}

			// Recherche dans la route en cours
			if (currentLanguage == null)
			{
				var viewData = RouteTable.Routes.GetRouteData(HttpContext);
				if (viewData.Route is Route)
				{
					currentLanguage = (string)((Route)viewData.Route).Defaults["language"];
				}
			}

			// Recherche en fonction de la langue par defaut du navigateur
			if (currentLanguage == null)
			{
				if (HttpContext.Request.UserLanguages.IsNotNullOrEmpty())
				{
					var userLanguage = HttpContext.Request.UserLanguages.First();
					currentLanguage = userLanguage.Substring(0, 2).ToLower();

					// Verification de l'apparatenance aux languages supportés
					if (!LocalizationService.SupportedLanguageList.Any(i => i.Equals(currentLanguage, StringComparison.InvariantCultureIgnoreCase)))
					{
						currentLanguage = GlobalConfiguration.Configuration.Settings.Language.Name;
					}
				}
			}

			// Recherche dans les langues supportées
			var language = GlobalConfiguration.Configuration.Settings.Language;
			try
			{
				if (currentLanguage != null)
				{
					language = ERPStore.Models.Language.GetByName(currentLanguage);
				}
			}
			catch
			{
			}
			var ci = new System.Globalization.CultureInfo(language.Id);

			// Fixe la culture du thread en cours
			// Change le format de date et autres
			System.Threading.Thread.CurrentThread.CurrentCulture = ci;
			System.Threading.Thread.CurrentThread.CurrentUICulture = ci;

			if (currentLanguage.IsNullOrTrimmedEmpty())
			{
				currentLanguage = ci.TwoLetterISOLanguageName.ToLower();
			}

			if (HttpContext.Items["language"] == null)
			{
				HttpContext.Items.Add("language", currentLanguage);
			}
			else
			{
				HttpContext.Items["language"] = currentLanguage;
			}
		}
	}
}
